/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#ifndef _INC_AK_EVT_CAST_
#define	_INC_AK_EVT_CAST_

#include "ak_types.h"
#include "ak_queue.h"
#include "ak_lock.h"
#include "ak_mem.h"
#include "ak_evt.h"
#include "ak_htbl.h"

#ifdef __cplusplus
extern "C" {
#endif


/* The MultiCast & BroadCast Process 
** 1. Reduce the Event Count.
** To reduce the Event Count, We don't use the EventQ, but the ObjectQ.
** Mapping the Event to each Object in the Queue.
** The Event should be Temp Storage in the Process Queue.
** The Event Queue should Support the Same Priority of Critical/High/Medium/Low.
** 
** 2. Schedule Requirement.
** We shouldn't Cycle Process all the Bunch Objects. but to Seperate them into different Group.
** Each time, only the Group's Objects should be Sched.
** In Given Time, In Given Count.
** The Scheduler will Loop the Groups, at the same time, An Cancel could be Processed Correctly.
** The Cursor is Used to Locate the Schedule Process.
*/
typedef struct{
	/* Wake & Lock */
	_t_sysSemB 		* 	wake;
	_t_sysCS 			lock;

	/* Event Queue */
	_t_blist 			que;

	/* Sche */
	unsigned int		batch;
	unsigned int		eStat;

	/* Event Entry : Handle */
	_t_cbentry 			eProc;
}_t_sEvtCast;


#define	_SEvtCast_Count(pEvtCast)			((pEvtCast)->que.count)
#define	_SEvtCast_IsEmpty(pEvtCast)			((pEvtCast)->que.count == 0)

#define _SEvtCast_Wake(pEvtCast) 	\
do{ \
	SYS_SEM_B_GIVE((pEvtCast)->wake);\
}while(0)

/* When EnQue Fail, Rem to Fail-Proc the Event */
#define _SEvtCast_EnQue(pEvtCast, pMi, vRet) \
do{ \
	vRet = 0;\
	SYS_ENTER_CS(&((pEvtCast)->lock));	\
	BLST_ADD2T(&((pEvtCast)->que), &((pMi)->aNode));\
	SYS_LEAVE_CS(&((pEvtCast)->lock));	\
	_SEvtCast_Wake(pEvtCast);	\
}while(0)


typedef struct{
	/* The EvtQ Type: Will be Checked as the Event is Async Disp. */
	int 			type;

	/* Enviorment : Will be Checked as the Event is Async Disp, will Force a Sync Event into the Async.
	** 1. Src Obj.Env 	= 	Dst Obj.Env (Sync ).
	** 2. Src Obj.Env 	!=	Dst Obj.Env (Async).
	** How to Get an Object's Env.
	** Obj.Env = Obj.EvtQ->pEnv.
	*/
	_t_sEnv		* 	pEnv;
	
	/* The Cast of Diff Priority */
	_t_sEvtCast 	pri[_SEvent_Pri_Max];

	/* Pool for the Event : Be Carefult of the Event's -> IE's -> Msg Pointer (Dynamic), 
	** When Free may Be Freed Multi-Times ?????
	** 1. Changing the Event's Dynamic --> Static
	** 2. Adding Reference Counter? Must Have the Ack, When Ack, Counter--, the Main/Source Task will Free It.
	** 3. Just Malloc At the Source, Alloc --> Copy, When Cast Processed, Just Free the Instance.
	*/

	/* The Object Hash & Group */
	_t_hTblCaS 			caTbl;
}_t_sEvtMC;

extern	int 	SEvtMc_SetTraceLvl(int lvl);
extern	int 	SEvtMc_GetTraceLvl(void);

extern	int 	SEvtMc_Init(_t_sEvtMC * pEvtMC, _t_sEnv * pEnv, _t_cbentry * eProc[_SEvent_Pri_Max]);
extern	int 	SEvtMc_ObjAdd(_t_sEvtMC * pEvtMC, struct _t_sObjSlot * pObjSlot);
extern	int 	SEvtMc_ObjDel(_t_sEvtMC * pEvtMC, struct _t_sObjSlot * pObjSlot);

extern	int 	SEvtMc_Sche(_t_sEvtMC * pEvtMC);

/* We Couldn't Call Cancel in the Callback, It's reent Dangerous ! */
extern	int 	SEvtMc_Cancel(_t_sEvtMC * pEvtMC, unsigned int priority, unsigned int type, unsigned int casId);

extern	int 	SEvtMc_PostMsg(_t_sEvtMC * pEvtMC, _t_sEvent * pIn, void * pMsg, unsigned int lMsg);


#ifdef __cplusplus
}
#endif

#endif


